﻿/*
 * Created by SharpDevelop.
 * User: Администратор
 * Date: 28.03.2011
 * Time: 11:22
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.IO;
using NLog;
using Video;


namespace Video.FLV
{
	/// <summary>
	/// Description of Decoder.
	/// </summary>
	public class Decoder:IDisposable
	{
		Logger log;
		VideoStream videoStream;
		
		public Decoder(string inFilePath)
		{
			videoStream = new VideoStream(inFilePath);
			log =  LogManager.GetCurrentClassLogger();
		}
		
		public byte GetHighTetra(byte source){
			byte distination = (byte)(source >> 4);
			return distination;
		}
		
		public byte GetLowTetra(byte source){
			byte distination = (byte)(source & 15);
			return distination;
		}
		
		public FLVHeader GetHeader(){
			FLVHeader temp = new FLVHeader();
			temp.Signature1 = videoStream.avio_r8();
			temp.Signature2 = videoStream.avio_r8();
			temp.Signature3 = videoStream.avio_r8();
			temp.Version = videoStream.avio_r8();
			temp.TypeFlags = videoStream.avio_r8();
			//temp.TypeFlagsAudio = stream.ReadByte();
			//temp.TypeFlagsReserved1 = stream.ReadByte();
			//temp.TypeFlagsVideo = stream.ReadByte();
			temp.DataOffset = videoStream.avio_rb32();
			
			//get first TagSize. Always 0
			
			
			log.Info("----FLV Heade----");
			log.Debug("Signature1: " + temp.Signature1);
			log.Debug("Signature2: " + temp.Signature2);
			log.Debug("Signature3: " + temp.Signature3);
			log.Debug("Version: " + temp.Version);
			log.Debug("TypeFlags: " + temp.TypeFlags);
			
			log.Info("----FLV body----");
			videoStream.avio_rb32();
			
			
			return temp;
		}
		
		public FLVBody GetBody(){
			
			FLVBody temp = new FLVBody();
			
			temp.FlvTag = GetTag();
			//if(temp.FlvTag.TagType==9){
				//пока здесь считаем
				//byte[] buf = new byte[temp.FlvTag.DataSize-1];
				//buf = stream.ReadBytes((int)temp.FlvTag.DataSize-1);
				//newstream.Write(buf);
			//}
			//else{
				
			//}		
			temp.PreviousTagSize = videoStream.avio_rb32();
			return temp;
		}
		
		public FLVTag GetTag(){
			FLVTag temp = new FLVTag();
			temp.TagType = videoStream.avio_r8();
			temp.DataSize = videoStream.avio_rb24();
			temp.Timestamp = videoStream.avio_rb24();
			temp.TimestampExtended = videoStream.avio_r8();
			temp.StreamID = videoStream.avio_rb24();
			
			if(temp.TagType == 9){
			log.Info("----FLV TAG----");
			log.Debug("TagType: " + temp.TagType);
			log.Debug("DataSize: " + temp.DataSize);
			log.Debug("Timestamp: " + temp.Timestamp);
			log.Debug("TimestampExtended: " + temp.TimestampExtended);
			log.Debug("StreamID: " + temp.StreamID);
			}
			switch (temp.TagType) {
				case 8:
					videoStream.avio_seek((int)temp.DataSize, SeekOrigin.Current);
					break;
				case 9:
					temp.VideoData = GetVideo();		
					//next tag
					videoStream.avio_seek((int)temp.DataSize-1, SeekOrigin.Current);
					break;
				case 18:
					videoStream.avio_seek((int)temp.DataSize, SeekOrigin.Current);
					break;
				default:
					videoStream.avio_seek((int)temp.DataSize, SeekOrigin.Current);
					log.Info("Unknow tag type: "+temp.TagType);
					break;
			}
			
			return temp;
		}
		
		public FLVVideoData GetVideo(){
			FLVVideoData temp = new FLVVideoData();
			byte tempbyte = videoStream.avio_r8();
			temp.FrameType = GetHighTetra(tempbyte);
			temp.CodecID = GetLowTetra(tempbyte);
			
			log.Info("----VIDEODATA----");
			log.Debug("FrameType: " + temp.FrameType);
			log.Debug("CodecID: " + temp.CodecID);
			
			switch (temp.CodecID) {
				case 2:
					log.Info("H263VIDEOPAKET");
					break;
				case 3:
					log.Info("SCREENVIDEOPAKET");
					break;
				case 4:
					log.Info("VP6FLVVIDEOPAKET");
					break;
				case 5:
					log.Info("VP6FLVALPHAVIDEOPAKET");
					break;
				case 6:
					log.Info("SCREENV2VIDEOPAKET");
					break;
				case 7:
					log.Info("AVCVIDEOPAKET");
					break;
				default:
					log.Info("Unknow paket type: "+temp.CodecID);
					break;
			}
			
			return temp;
		}
		
		
		public void GoToNextTag(FLVTag tag){
			videoStream.avio_seek((int)tag.DataSize, SeekOrigin.Current);
		}
		
		public bool isEnd(){
			if(videoStream.inVideoStream.PeekChar()==-1){
				return true;
			}
			return false;
		}
		
		public void Dispose()
		{
		}
	}
}
